package com.code.generation.service.impl;

import com.code.generation.constant.Constants;
import com.code.generation.constant.FileConstants;
import com.code.generation.dto.CreateDTO;
import com.code.generation.dto.DataBaseInfo;
import com.code.generation.service.BootService;
import com.code.generation.utils.*;
import com.code.generation.vo.Settings;
import com.code.generation.vo.db.DataBaseVO;
import com.code.generation.vo.table.HtmlTable;
import com.code.generation.vo.table.Table;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;

import java.io.File;
import java.sql.Connection;
import java.text.DateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ProjectName: codegeneration
 * @Package: com.code.generation.service
 * @Description:
 * @Author: DongJW
 * @CreateDate: 2020/11/29 11:31
 * @Version: 1.0
 */
@Service
public class BootServiceImpl implements BootService {

    @Override
    public Boolean create(CreateDTO createDTO) throws Exception{
        DataBaseInfo dataBaseInfo = createDTO.getDataBaseInfo();
        if (null==dataBaseInfo){
            throw new RuntimeException("数据库信息为空！");
        }
        DataBaseVO dataBaseVO = buildDataBase(dataBaseInfo.getDataBaseType(),
                dataBaseInfo.getIp(),
                dataBaseInfo.getPort(),
                dataBaseInfo.getDb(),
                dataBaseInfo.getUsername(),
                dataBaseInfo.getPassword()
        );

        //获取数据库源数据
        Connection connection = JDBCUtil.getConnection(dataBaseVO);

        //获取模板路径
        String templateDir = TempUtils.getTemplateDir(createDTO.getTemplateType());

        //初始化Configuration
        ConfigurationUtils.init(templateDir);

        try {
            //获取数据库信息及其表信息
            List<Table> tableInfos = JDBCUtil.getTableInfo(connection);

            List<HtmlTable> htmlTables = preparationHtmlDate(tableInfos);
            //为每一张表生成文件
            for (Table tableInfo : tableInfos) {
                //构造数据模型
                Map<String, Object> dataModel = getDataModel(tableInfo, createDTO ,dataBaseVO);
                dataModel.put("htmlTables",htmlTables);
                //代码生成
                scanAndGenerator(dataModel,templateDir,createDTO.getOutPath());
            }

            //生成layui
            String outPath = createDTO.getOutPath();
            String projectName = createDTO.getProjectName();
            String layuiPath1 = ResourceUtils.getURL("classpath:").getPath()+File.separator+"static"+File.separator+"layui";
            String layuiPath2 = outPath+File.separator+ projectName+File.separator+"src"+File.separator+"main"+File.separator+"resources"+File.separator+"static"+File.separator+"layui";
            FileUtils.copyFolder(layuiPath1,layuiPath2);

        }finally {
            //生成项目
            JDBCUtil.close(connection);
            System.out.println("关闭连接");
        }
        return false;
    }

    /**
     * 准备生成前端文件的数据
     * @param tableInfos 表集合
     * @return 文件数据
     */
    private List<HtmlTable> preparationHtmlDate(List<Table> tableInfos){
        //为生成前端文件准备数据
        return tableInfos.stream().map(table -> {
            HtmlTable htmlTable = new HtmlTable();
            //表名首字母大写
            String className = table.getTableNameExt();
            htmlTable.setTableName(className);
            //表名首字母小写
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append((className.substring(0, 1)).toLowerCase()).append((className.substring(1)));
            String htmlTableNameExt = stringBuilder.toString();
            htmlTable.setTableNameExt(htmlTableNameExt);
            htmlTable.setListPath(FileConstants.SEPARATOR + htmlTableNameExt + FileConstants.LIST + className);
            htmlTable.setTableNameCN(StringUtils.isEmpty(table.getComment()) ? className : table.getComment());
            return htmlTable;
        }).collect(Collectors.toList());
    }


    /**
     *
     * @param dataModel dataModel
     * @param tempalteDir 模板文件夹
     * @param outPath 输出路径
     * @throws Exception 异常
     */
    private void scanAndGenerator(Map<String,Object> dataModel,String tempalteDir,String outPath)throws Exception{
        List<File> paths = new ArrayList<>();
        List<File> templateFiles = FileUtils.getAllFiles(new File(tempalteDir), paths);
        //对每一个模板进行文件生成
        for (File templateFile : templateFiles) {
            executGenerator(dataModel,templateFile,tempalteDir,outPath);
        }
    }

    /**
     *  生成文件
     * @param dataModel 数据模型
     * @param templateFile 模板文件
     * @param tempalteDir 模板文件夹
     * @param outPath 输出路径
     * @throws Exception 异常
     */
    private void executGenerator(Map<String,Object> dataModel,File templateFile,
                                 String tempalteDir,String outPath)throws Exception{

        //字符串模板路径，这是个包含需要替换包名的模板路径，不包含根目录
        String templateName = templateFile.getAbsolutePath()
                .replace(tempalteDir.replace(FileConstants.SEPARATOR, File.separator), FileConstants.EMPTY);

        //生成字符串模路径
        String outStringWriter = ConfigurationUtils.processStringTemplate(templateName, dataModel);

        //取出名称
        String substring = outStringWriter.substring(outStringWriter.lastIndexOf(FileConstants.POINT));

        //将字符串模板流中路径中的“.”替换为文件分隔符“/”
        String outFileName = outStringWriter.replace(substring, FileConstants.EMPTY).replace(FileConstants.POINT,File.separator) + substring;

        //生成代码
        ConfigurationUtils.generatorFile(templateName, outPath, outFileName, dataModel);
    }


    /**
     * 根据表源数据生成数据模型
     * @param table 表源数据
     * @return 数据模型
     */
    private Map<String,Object> getDataModel(Table table,CreateDTO createDTO,DataBaseVO dataBaseVO){
        Map<String,Object> dataModel = new HashMap<>();
        dataModel.putAll(PropertitesUtil.propsMap);
        dataModel.put("table",table);
        dataBaseVO.setType(createDTO.getDataBaseInfo().getDataBaseType());
        dataModel.put("database",dataBaseVO);
        //将路径信息装进模型
        Settings settings = new Settings();

        settings.setAuthor(createDTO.getAuthor());
        settings.setpPackage(createDTO.getpPackage());
        settings.setProjectName(createDTO.getProjectName());
        settings.setProjectComment(createDTO.getProjectComment());
        dataModel.putAll(settings.getSettingMap());

        DateFormat df=DateFormat.getDateTimeInstance();
        dataModel.put("createDate",df.format(new Date()));
        dataModel.put("ClassName",table.getTableNameExt());

        return dataModel;
    }

    /**
     * 构建数据库连接实体
     * @param dbType 数据库类型
     * @param ip ip
     * @param port 端口
     * @param db 数据库名字
     * @param username 用户名
     * @param password 密码
     * @return 连接实体
     */
    private DataBaseVO buildDataBase(String dbType,String ip,String port,String db,String username,String password){
        DataBaseVO dataBaseVO = new DataBaseVO();
        String url = null;
        String driver = null;
        if (Constants.DB_TYPE_MYSQL.equals(dbType)){
            driver = Constants.DB_DRIVER_MYSQL;
            url = Constants.DB_URL_MYSQL.replace("[ip]", ip).replace("[port]", port).replace("[dbname]", db);
        }else if (Constants.DB_TYPE_ORACLE.equals(dbType)){
            driver = Constants.DB_DRIVER_ORACLE;
            url = Constants.DB_URL_ORACLE.replace("[ip]", ip).replace("[port]", port).replace("[dbname]", db);
        }
        dataBaseVO.setDriver(driver);
        dataBaseVO.setUrl(url);
        dataBaseVO.setUsername(username);
        dataBaseVO.setPassword(password);
        return dataBaseVO;
    }
}
